﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Noris.Schedule.Support.Parser
{
    #region class ParserDefaultSetting : Generátor settingů pro obecný parser pro různé konkrétní jazyky.
    /// <summary>
    /// ParserDefaultSetting : Generátor settingů pro různé konkrétní jazyky.
    /// </summary>
    public static class ParserDefaultSetting
    {
        #region Public static property, které vracejí settings
        /// <summary>
        /// ParserSetting pro Microsoft T-SQL.
        /// </summary>
        public static ParserSetting MsSql { get { return _GetSettingMsSql(false); } }
        /// <summary>
        /// ParserSetting pro Microsoft T-SQL.
        /// Zajistí sloučení názvů databázových objektů v případě, kdy okolo vnitřní tečky jsou mezery: "lcs . tabulka . sloupec".
        /// </summary>
        public static ParserSetting MsSqlMerged { get { return _GetSettingMsSql(true); } }
        #endregion
        #region Konstanty
        public const string SQL_ = "Sql";
        public const string SQL_CODE = "SqlCode";
        public const string SQL_LITERAL = "SqlLiteral";
        public const string SQL_SYSNAME = "SqlSysName";
        public const string SQL_PARENTHESIS = "SqlParenthesis";
        public const string SQL_COMMENTLINE = "SqlCommentLine";
        public const string SQL_COMMENTBLOCK = "SqlCommentBlock";
        #endregion
        #region Generátor settings pro MsSql
        private static ParserSetting _GetSettingMsSql(bool enableMergeDotSpaceText)
        {
            ParserSetting setting = new ParserSetting("MsSql", SQL_CODE);
            AddSettingMsSql(setting, enableMergeDotSpaceText);
            return setting;
        }
        /// <summary>
        /// Do daného settingu vloží položky (definice segmentů) pro jazyk T-SQL.
        /// Vrací root segment této definice.
        /// </summary>
        /// <param name="setting"></param>
        public static ParserSegmentSetting AddSettingMsSql(ParserSetting setting)
        {
            return AddSettingMsSql(setting, false);
        }
        /// <summary>
        /// Do daného settingu vloží položky (definice segmentů) pro jazyk T-SQL.
        /// Vrací root segment této definice.
        /// </summary>
        /// <param name="setting"></param>
        public static ParserSegmentSetting AddSettingMsSql(ParserSetting setting, bool enableMergeDotSpaceText)
        {
            ParserSegmentSetting segment;
            ParserSegmentSetting result;

            // Společná data pro SQL_CODE a SQL_PARENTHESIS, které obě mohou obsahovat SQL kód:
            string[] blanks = new string[] { " ", "\t", "\r", "\n" };
            string[] delimiters = new string[] { ",", "+", "-", "*", "/", "<", "=", ">", "<=", ">=", "<>", "%" };

            // SQL Kód:
            segment = new ParserSegmentSetting(SQL_CODE);
            segment.Blanks = blanks.ToArray();
            segment.Delimiters = delimiters.ToArray();
            segment.EndWith = new string[] { ";" };
            segment.InnerSegmentsNames = new string[] { SQL_LITERAL, SQL_SYSNAME, SQL_PARENTHESIS, SQL_COMMENTLINE, SQL_COMMENTBLOCK };
            segment.Keywords = GetKeywordsSqlLanguage().ToArray();
            segment.KeywordsCaseSensitive = false;
            segment.EnableMergeDotSpaceText = enableMergeDotSpaceText;
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkGreen), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.Regular) },
                                null);
            segment.AddRtfCodes(ParserSegmentValueType.Delimiter,
                                new RtfItem[] { RtfItem.NewForeColor(Color.Magenta) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkGreen) });
            segment.AddRtfCodes("Keyword",
                                new RtfItem[] { RtfItem.NewForeColor(Color.MediumBlue) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkGreen) });
            setting.SegmentSettingAdd(segment);
            result = segment;                         // Výstup této metody

            // Stringy:
            segment = new ParserSegmentSetting(SQL_LITERAL);
            segment.BeginWith = "'";
            segment.EndWith = new string[] { "'" };
            segment.SpecialTexts = new ParserSegmentSpecialTexts[] { new ParserSegmentSpecialTexts("''", "'") };
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.Red), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.BoldOnly) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.Empty) });
            setting.SegmentSettingAdd(segment);

            // Hranaté závorky = systémové jméno:
            segment = new ParserSegmentSetting(SQL_SYSNAME);
            segment.BeginWith = "[";
            segment.EndWith = new string[] { "]" };
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkSlateGray), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.Regular) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.Empty) });
            setting.SegmentSettingAdd(segment);

            // Kulaté závorky = funkce, výrazy, a pozor => i vnořené selecty, takže má charakter i code:
            segment = new ParserSegmentSetting(SQL_PARENTHESIS);
            segment.BeginWith = "(";
            segment.Blanks = blanks.ToArray();
            segment.Delimiters = delimiters.ToArray();
            segment.EndWith = new string[] { ")" };
            segment.InnerSegmentsNames = new string[] { SQL_LITERAL, SQL_SYSNAME, SQL_PARENTHESIS, SQL_COMMENTLINE, SQL_COMMENTBLOCK };
            segment.Keywords = GetKeywordsSqlLanguage().ToArray();
            segment.KeywordsCaseSensitive = false;
            segment.EnableMergeDotSpaceText = enableMergeDotSpaceText;
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkSlateBlue), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.Regular) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.Empty) });
            segment.AddRtfCodes("Keyword",
                                new RtfItem[] { RtfItem.NewForeColor(Color.MediumBlue) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkGreen) });
            segment.AddRtfCodes(ParserSegmentValueType.Delimiter,
                                new RtfItem[] { RtfItem.NewForeColor(Color.Magenta) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkSlateBlue) });
            setting.SegmentSettingAdd(segment);

            // Komentář řádkový (začíná --, končí koncem řádku, přičemž konec není ukládán do segmentu, ale zpracuje se jako další text):
            segment = new ParserSegmentSetting(SQL_COMMENTLINE);
            segment.BeginWith = "--";
            segment.EndWith = new string[] { "\r\n", "\r", "\n" };
            segment.EndOutside = true;
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkSlateGray), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.Regular), RtfItem.NewHighlight(Color.FromArgb(226, 226, 234)) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.Empty), RtfItem.NewHighlight(Color.Empty) });
            setting.SegmentSettingAdd(segment);

            // Komentář blokový (začíná /*, končí */), otázka je zda může obsahovat vnořené blokové komentáře => rozhodnutí zní ANO:
            segment = new ParserSegmentSetting(SQL_COMMENTBLOCK);
            segment.BeginWith = "/*";
            segment.EndWith = new string[] { "*/" };
            segment.InnerSegmentsNames = new string[] { SQL_COMMENTBLOCK };
            segment.AddRtfCodes(ParserSegmentValueType.Text,
                                new RtfItem[] { RtfItem.NewForeColor(Color.DarkSlateGray), RtfItem.NewFont("Courier New CE"), RtfItem.NewFontStyle(RtfFontStyle.Regular), RtfItem.NewHighlight(Color.FromArgb(226, 226, 234)) },
                                new RtfItem[] { RtfItem.NewForeColor(Color.Empty), RtfItem.NewHighlight(Color.Empty) });
            setting.SegmentSettingAdd(segment);

            // Vrátíme segment, který je rootem této entity
            return result;
        }
        /// <summary>
        /// Vrátí pole klíčových slov jazyka SQL.
        /// </summary>
        /// <returns></returns>
        public static List<string> GetKeywordsSqlLanguage()
        {
            #region Text of keywords : seznam klíčových slov pochází z článku SQL Helpu, a lze jej odtamtud snadno aktualizovat
            string keywords = @"
ADD
 EXISTS
 PRECISION
 
ALL
 EXIT
 PRIMARY
 
ALTER
 EXTERNAL
 PRINT
 
AND
 FETCH
 PROC
 
ANY
 FILE
 PROCEDURE
 
AS
 FILLFACTOR
 PUBLIC
 
ASC
 FOR
 RAISERROR
 
AUTHORIZATION
 FOREIGN
 READ
 
BACKUP
 FREETEXT
 READTEXT
 
BEGIN
 FREETEXTTABLE
 RECONFIGURE
 
BETWEEN
 FROM
 REFERENCES
 
BREAK
 FULL
 REPLICATION
 
BROWSE
 FUNCTION
 RESTORE
 
BULK
 GOTO
 RESTRICT
 
BY
 GRANT
 RETURN
 
CASCADE
 GROUP
 REVERT
 
CASE
 HAVING
 REVOKE
 
CHECK
 HOLDLOCK
 RIGHT
 
CHECKPOINT
 IDENTITY
 ROLLBACK
 
CLOSE
 IDENTITY_INSERT
 ROWCOUNT
 
CLUSTERED
 IDENTITYCOL
 ROWGUIDCOL
 
COALESCE
 IF
 RULE
 
COLLATE
 IN
 SAVE
 
COLUMN
 INDEX
 SCHEMA
 
COMMIT
 INNER
 SECURITYAUDIT
 
COMPUTE
 INSERT
 SELECT
 
CONSTRAINT
 INTERSECT
 SESSION_USER
 
CONTAINS
 INTO
 SET
 
CONTAINSTABLE
 IS
 SETUSER
 
CONTINUE
 JOIN
 SHUTDOWN
 
CONVERT
 KEY
 SOME
 
CREATE
 KILL
 STATISTICS
 
CROSS
 LEFT
 SYSTEM_USER
 
CURRENT
 LIKE
 TABLE
 
CURRENT_DATE
 LINENO
 TABLESAMPLE
 
CURRENT_TIME
 LOAD
 TEXTSIZE
 
CURRENT_TIMESTAMP
 MERGE
 THEN
 
CURRENT_USER
 NATIONAL
 TO
 
CURSOR
 NOCHECK 
 TOP
 
DATABASE
 NONCLUSTERED
 TRAN
 
DBCC
 NOT
 TRANSACTION
 
DEALLOCATE
 NULL
 TRIGGER
 
DECLARE
 NULLIF
 TRUNCATE
 
DEFAULT
 OF
 TSEQUAL
 
DELETE
 OFF
 UNION
 
DENY
 OFFSETS
 UNIQUE
 
DESC
 ON
 UNPIVOT
 
DISK
 OPEN
 UPDATE
 
DISTINCT
 OPENDATASOURCE
 UPDATETEXT
 
DISTRIBUTED
 OPENQUERY
 USE
 
DOUBLE
 OPENROWSET
 USER
 
DROP
 OPENXML
 VALUES
 
DUMP
 OPTION
 VARYING
 
ELSE
 OR
 VIEW
 
END
 ORDER
 WAITFOR
 
ERRLVL
 OUTER
 WHEN
 
ESCAPE
 OVER
 WHERE
 
EXCEPT
 PERCENT
 WHILE
 
EXEC
 PIVOT
 WITH
 
EXECUTE
 PLAN
 WRITETEXT
 

";
            #endregion
            return SplitTextToRows(keywords, ' ', '\t', '\r', '\n');
        }
        /// <summary>
        /// Vrátí daný text rozdělený na pole stringů, kde oddělovače jsou určeny. Pole se dělí s options: RemoveEmptyEntries.
        /// </summary>
        /// <param name="keywords"></param>
        /// <param name="separators"></param>
        /// <returns></returns>
        public static List<string> SplitTextToRows(string keywords, params char[] separators)
        {
            return ParserSetting.SplitTextToRows(keywords, separators);
        }
        #endregion
    }
    #endregion
}
